# _*_ coding: utf-8 _*_
"""
author: lianGang
email: 1542652663@qq.com
cookBook第六章 数据编码和处理
"""

# from collections import OrderedDict
# import json
#
#
# s = '{"name": "ACME", "shares": 50, "price": 490.1}'
#
# data = json.loads(s,object_hook=OrderedDict)
#
# class JSONObject:
#     def __init__(self, d):
#         self.__dict__ = d
#
#
# # data = json.loads(s, object_hook=JSONObject)
#
# # 对象实例不可直接JSON序列化
# class Point:
#     def __init__(self, x, y):
#         self.x = x
#         self.y = y
#
#
# def serialize_instance(obj):
#     d = {  '__classname__': type(obj).__name__}
#     d.update(vars(obj))
#     return d
#
#
# # 反向获取实例
# classes = {
#     'Point': Point
# }
#
#
# def unserialize_object(d):
#     clsname = d.pop('__classname__', None)
#     if clsname:
#         cls = classes[clsname]
#         obj = cls.__new__(cls) # make instance without calling __init__
#         for key, value in d.items():
#             setattr(obj, key, value)
#         return obj
#     else:
#         return d
#
#
# p = Point(2,3)
# s = json.dumps(p, default=serialize_instance)
# a = json.loads(s, object_hook=unserialize_object)
# print(a.x, a.y)


# increment_parse 使用迭代器和生成器处理大文件XML
from xml.etree.ElementTree import iterparse

def parse_and_remove(filename, path):
    path_parts = path.split('/')
    doc = iterparse(filename, ('start', 'end'))
    # skip the root element
    next(doc)
    tag_stack = []
    elem_stack = []
    for event, elem in doc:
        if event == 'start':
            tag_stack.append(elem.tag)
            elem_stack.append(elem)
        elif event == 'end':
            if tag_stack == path_parts:
                yield elem
                elem_stack[-2].remove(elem)
            try:
                tag_stack.pop()
                elem_stack.pop()
            except IndexError:
                pass


from xml.etree.ElementTree import parse
from collections import Counter

# old 全读取到内存处理
potholes_by_zip = Counter()

doc = parse('potholes.xml') # old

# doc = parse_and_remove('potholes.xml) # new 增量读取

for pothole in doc.iterfind('row/row'):
    potholes_by_zip[pothole.findtext('zip')] += 1
for zipcode, num in potholes_by_zip.most_common():
    print(zipcode, num)


#6.7 将字典转换位XML
from xml.etree.ElementTree import Element

def dict_to_xml(tag, d):
    elem = Element(tag)
    for key,val in d.items():
        child = Element(key)
        child.text = str(val)
        elem.append(child)
    return elem

s = { 'name': 'GOOG', 'shares': 100, 'price':490.1 }

from xml.etree.ElementTree import tostring

# 编码和解码十六进制数
import base64

s = b'hello world'
h = base64.b16encode(s)
print(h)
base64.b16decode(h)

# 8.11 读写二进制数组数据
from struct import Struct

def write_records(records, format, f):
    """
    write a sequence of tuples to a binary file of structures
    :param records:
    :param format:
    :param f:
    :return:
    """
    records_struct = Struct(format)
    for r in records:
        f.write(records_struct.pack(*r))

records = [(1,2.3, 4.5),
           (6, 7.8, 9.0),
           (12, 13.4, 56.7)]
with open('data.b', 'wb') as f:
    write_records(records, '<idd', f)

# 增量读取文件并返回一个元组对象
def read_records(format, f):
    record_struct = Struct(format)
    chunks = iter(lambda: f.read(record_struct.size), b'')
    return (record_struct.unpack(chunk) for chunk in chunks)

with open('data.b', 'rb') as f:
    for rec in read_records('<idd', f):
        pass
